home *** CD-ROM | disk | FTP | other *** search
/ Download Now 8 / Download Now V8.iso / Program / InternetTools / ApacheWebServer1.3.6 / apache_1_3_6_win32.exe / _SETUP.1 / install.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-16  |  19.2 KB  |  668 lines

  1. /* Apache Installer */
  2.  
  3. /*
  4.  * 26/06/97 PCS 1.000 Initial version
  5.  * 22/02/98 PCS 1.001 Used the excellent NTemacs to apply proper formating
  6.  * 04/05/98 PCS 1.002 Copy conf files to *.conf.default, then to *.conf
  7.  * 16/02/99 PCS 1.003 Add logging to "install.log" in the installed directory
  8.  */
  9.  
  10. #define VERSION ( "1.003 " __DATE__ " " __TIME__ )
  11.  
  12. #include <windows.h>
  13. #include <winsock.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <direct.h>
  17. #include <time.h>
  18.  
  19. #include "conf.h"
  20. #include "ap.h"
  21.  
  22. #ifdef strftime
  23. #undef strftime
  24. #endif
  25.  
  26. /* Global to store the instance handle */
  27. HINSTANCE hInstance = NULL;
  28.  
  29. static char *szLogFilename = NULL;
  30. static FILE *fpLog = NULL;
  31.  
  32. void OpenLog(char *dir, char *fn)
  33. {
  34.     szLogFilename = malloc(strlen(dir) + 1 + strlen(fn) + 1);
  35.     sprintf(szLogFilename, "%s/%s", dir, fn);
  36.  
  37.     fpLog = fopen(szLogFilename, "a+");
  38. }
  39.  
  40. void LogMessage(char *fmt, ...)
  41. {
  42.     char buf[4000];
  43.     va_list ap;
  44.     struct tm *tms;
  45.     time_t nowtime;
  46.     char *bp = buf;
  47.     int rv;
  48.     int free = sizeof(buf);
  49.  
  50.     if (!fpLog) {
  51.     return;
  52.     }
  53.  
  54.     nowtime = time(NULL);
  55.     tms = localtime(&nowtime);
  56.     rv = strftime(bp, free, "%c", tms);
  57.     bp += rv;
  58.     free -= rv;
  59.     if (free) {
  60.         *bp++ = ' ';
  61.     free--;
  62.     }
  63.  
  64.     va_start(ap, fmt);
  65.     rv = ap_vsnprintf(bp, free, fmt, ap);
  66.     va_end(ap);
  67.  
  68.     free -= rv;
  69.  
  70.     fprintf(fpLog, "%s\n", buf);
  71. }
  72.  
  73. void CloseLog(void)
  74. {
  75.     if (fpLog) {
  76.     fclose(fpLog);
  77.     }
  78. }
  79.  
  80. /*
  81.  * MessageBox_error() is a helper function to display an error in a 
  82.  * message box, optionally including a Win32 error message. If
  83.  * the "opt" argument is value AP_WIN32ERROR then get the last Win32
  84.  * error (with GetLastError()) and add it on to the end of
  85.  * the output string. The output string is given as a printf-format
  86.  * and replacement arguments. The hWnd, title and mb_opt fields are 
  87.  * passed on to the Win32 MessageBox() call.
  88.  */
  89.  
  90. #define AP_WIN32ERROR 1
  91.  
  92. int MessageBox_error(HWND hWnd, int opt, char *title, 
  93.              int mb_opt, char *fmt, ...)
  94. {
  95.     char buf[1000];
  96.     va_list ap;
  97.     int free = sizeof(buf);       /* Number of bytes free in the buffer */
  98.     int rv;
  99.     char *p;
  100.  
  101.     va_start(ap, fmt);
  102.     rv = ap_vsnprintf(buf, sizeof(buf), fmt, ap);
  103.     va_end(ap);
  104.  
  105.     free -= rv;
  106.  
  107.     if (opt & AP_WIN32ERROR && free > 3) {
  108.       /* We checked in the "if" that we have enough space in buf for
  109.        * at least three extra characters.
  110.        */
  111.       p = buf + strlen(buf);
  112.       *p++ = '\r';
  113.       *p++ = '\r';
  114.       *p++ = '(';
  115.       free -= 3;
  116.       /* NB: buf is now not null terminated */
  117.  
  118.       /* Now put the error message straight into buf. This function
  119.        * takes the free buffer size as the 6th argument.
  120.        */
  121.       rv = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  122.                          NULL,
  123.                          GetLastError(),
  124.                          0,
  125.                          p,
  126.                          free,
  127.                          NULL);
  128.  
  129.       if (rv == 0) {
  130.           /* FormatMessage failed, so get rid of the "\r\r(" we just placed
  131.            * in the buffer, since there is no system error message.
  132.            */
  133.           p -= 3;
  134.           *p = '\0';
  135.           free += 3;
  136.       } else {
  137.           free -= rv;
  138.           p += rv;
  139.  
  140.           /* Strip any trailing \r or \n characters to make it look nice on
  141.            * the screen.
  142.            */
  143.           while (*(p-1) == '\r' || *(p-1) == '\n')
  144.               p--, free++;
  145.           *p = '\0';
  146.  
  147.           /* Append a trailing ) */
  148.           if (free >= 1) {
  149.               *p++ = ')';
  150.               *p++ = '\0';
  151.           }
  152.       }
  153.     }
  154.  
  155.     for (p = buf; *p; p++) {
  156.     if (*p == '\n' || *p == '\r') {
  157.         *p = ' ';
  158.     }
  159.     }
  160.     LogMessage("MSG %s", buf);
  161.  
  162.     return MessageBox(hWnd, buf, title, mb_opt);
  163. }
  164.  
  165. /*
  166.  * The next few functions handle expanding the @@ServerRoot@@ type
  167.  * sequences found in the distribution files. The main entry point
  168.  * is expandFile(), which is given a file to expand and the filename
  169.  * to write the expanded file it. It reads a line at a time, and
  170.  * if the line includes an "@@" sequence, calls expandLine() to
  171.  * expand the sequences.
  172.  *
  173.  * expandLine() looks for @@ sequences in the line, and when it finds
  174.  * one, looks for a corresponding entry in the replaceTable[]. If it
  175.  * finds one it writes the replacement value from the table into
  176.  * an output string.
  177.  *
  178.  * The helper function appendText() is used when expanding strings. It
  179.  * is called to copy text into an output buffer. If the output buffer
  180.  * is not big enough, it is expanded. This function also ensures that
  181.  * the output buffer is null terminated after each append operation.
  182.  *
  183.  * A table is used of values to replace, rather than just hardcoding
  184.  * the functionality, so we could replace additional values in the
  185.  * future.  We also take care to ensure that the expanded line can be
  186.  * arbitrary length (though at the moment the lines read from the
  187.  * configuration files can only be up to 2000 characters).
  188.  */
  189.  
  190. /*
  191.  * Table of items to replace. The "value" elements are filled in at runtime
  192.  * by FillInReplaceTable(). Note that the "tmpl" element is case
  193.  * sensitive.
  194.  */
  195.  
  196. typedef struct {
  197.     char *tmpl;
  198.     char *value;
  199. } REPLACEITEM;
  200. typedef REPLACEITEM *REPLACETABLE;
  201.  
  202. REPLACEITEM replaceHttpd[] = {
  203.     { "@@ServerRoot@@", NULL },    /* ServerRoot directory (i.e. install dir) */
  204.     { NULL, NULL }
  205. };
  206.  
  207. /*
  208.  * A relatively intelligent version of strcat, that expands the destination
  209.  * buffer if needed.
  210.  *
  211.  * On entry, ppBuf points to the output buffer, pnPos points to the offset
  212.  * of the current position within that buffer, and pnSize points to the
  213.  * current size of *ppBuf. pSrc points to the string to copy into the buffer,
  214.  * and nToCopy gives the number of characters to copy from pSrc.
  215.  *
  216.  * On exit, *ppBuf, *pnPos and *pnSize may have been updated if the output
  217.  * buffer needed to be expanded. The output buffer will be null terminated.
  218.  * Returns 0 on success, -1 on error. Does not report errors to the user.
  219.  */
  220.  
  221. int appendText(char **ppBuf, int *pnPos, int *pnSize, char *pSrc, int nToCopy)
  222. {
  223.     char *pBuf = *ppBuf;    /* output buffer */
  224.     int nPos = *pnPos;        /* current offset into pBuf */
  225.     int nSize = *pnSize;    /* current size of pBuf */
  226.  
  227.     while (nPos + nToCopy >= nSize) {
  228.     /* Not enough space, double size of output buffer. Note we use
  229.      * >= not > so that we have enough space for the NULL character
  230.      * in the output buffer */
  231.     char *pBufNew;
  232.  
  233.     pBufNew = realloc(pBuf, nSize * 2);
  234.     if (!pBufNew)
  235.         return -1;
  236.     nSize *= 2;
  237.  
  238.     /* Update the max size and buffer pointer */
  239.     *pnSize = nSize;
  240.     *ppBuf = pBuf = pBufNew;
  241.     }
  242.  
  243.     /* Ok, now we have enough space, copy the stuff */
  244.  
  245.     strncpy(pBuf+nPos, pSrc, nToCopy);
  246.     nPos += nToCopy;
  247.     *pnPos = nPos;        /* update current position */
  248.     pBuf[nPos] = '\0';        /* append trailing NULL */
  249.  
  250.     return 0;
  251. }
  252.  
  253. /*
  254.  * Expand all the sequences in an input line. Returns a pointer to the
  255.  * expanded line. The caller should free the returned data.
  256.  * The replaceTable argument is a table of sequences to expand.
  257.  *
  258.  * Returns NULL on error. Does not report errors to the user.
  259.  */
  260.  
  261. char *expandLine(char *in, REPLACETABLE replaceTable)
  262. {
  263.     REPLACEITEM *item;
  264.     char *pos;            /* current position in input buffer */
  265.     char *outbuf;        /* output buffer */
  266.     int outbuf_size;        /* current size of output buffer */
  267.     int outbuf_position;    /* current position in output buffer */
  268.     char *start;        /* position to copy from in input buffer */
  269.  
  270.     /* Create an initial output buffer. Guess that twice the input size
  271.      * is a good length, after expansion. Don't worry if we need more
  272.      * though, appendText() will expand as needed.
  273.      */
  274.     outbuf_size = strlen(in) * 2;
  275.     outbuf_position = 0;
  276.     outbuf = malloc(outbuf_size);
  277.     if (!outbuf)
  278.       return NULL;
  279.  
  280.     start = in;            /* mark the start of uncopied data */
  281.     pos = in;            /* current position in input buffer */
  282.  
  283.     while (1) {
  284.  
  285.     /* Look for '@@' sequence, or end of input */
  286.     if (*pos && !(*pos == '@' && *(pos+1) == '@')) {
  287.         pos++;
  288.         continue;
  289.     }
  290.  
  291.     if (!*pos) {
  292.         /* End of input string, copy the uncopied data */
  293.         if (appendText(&outbuf, &outbuf_position, &outbuf_size, 
  294.                start, pos-start) < 0) {
  295.         return NULL;
  296.         }
  297.         break;
  298.     }
  299.  
  300.     /* Found first @ of a possible token to replace. Look for end
  301.      * of the token
  302.      */
  303.     for (item = replaceTable; item->tmpl; ++item) {
  304.         if (!strncmp(pos, item->tmpl, strlen(item->tmpl)))
  305.         break;
  306.     }
  307.  
  308.     if (item->tmpl) {
  309.         /* Found match. First copy the uncopied data from the input
  310.          * buffer (start through to pos-1), then copy the expanded
  311.          * value. */
  312.         if (appendText(&outbuf, &outbuf_position, &outbuf_size,
  313.                start, pos-start) < 0) {
  314.         return NULL;
  315.         }
  316.         if (appendText(&outbuf, &outbuf_position, &outbuf_size,
  317.                item->value, strlen(item->value)) < 0) {
  318.         return NULL;
  319.         }
  320.  
  321.         /* Update current position to skip over the input buffer
  322.          * @@...@@ sequence, and update the "start" pointer to uncopied
  323.          * data
  324.          */
  325.         pos += strlen(item->tmpl);
  326.         start = pos;
  327.     } 
  328.     else {
  329.         /* The sequence did not exist in the replace table, so copy
  330.          * it as-is to the output.
  331.          */
  332.         pos++; 
  333.     }
  334.     }
  335.  
  336.     return outbuf;
  337. }
  338.  
  339. /*
  340.  * Some options to determine how we copy a file. Apart from OPT_NONE, these should
  341.  * be OR'able
  342.  */
  343.  
  344. typedef enum { 
  345.     OPT_NONE = 0, 
  346.     OPT_OVERWRITE = 1,        /* Always overwrite destination file */
  347.     OPT_EXPAND = 2,        /* Expand any @@...@@ tokens in replaceHttpd */
  348.     OPT_DELETESOURCE = 4,   /* Delete the source file after the copy */
  349.     OPT_SILENT = 8,        /* Don't tell use about failures */
  350. } options_t;
  351.  
  352. /* 
  353.  * Copy a file, expanding sequences from the replaceTable argument.
  354.  * Returns 0 on success, -1 on error. Reports errors to user.
  355.  */
  356. #define MAX_INPUT_LINE 2000
  357. int WINAPI ExpandConfFile(HWND hwnd, LPSTR szInst, LPSTR szinFile, LPSTR szoutFile, REPLACETABLE replaceTable, options_t options)
  358. {
  359.     char inFile[_MAX_PATH];
  360.     char outFile[_MAX_PATH];
  361.     char inbuf[MAX_INPUT_LINE];
  362.     FILE *infp;
  363.     FILE *outfp;
  364.  
  365.     ap_snprintf(inFile, sizeof(inFile), "%s\\%s", szInst, szinFile);
  366.     ap_snprintf(outFile, sizeof(outFile), "%s\\%s", szInst, szoutFile);
  367.  
  368.     if (!(infp = fopen(inFile, "r"))) {
  369.     MessageBox_error(hwnd, 
  370.              AP_WIN32ERROR,
  371.              "Installation Problem",
  372.              MB_OK | MB_ICONSTOP,
  373.              "Cannot read file %s", inFile);
  374.     return -1;
  375.     }
  376.     if (! (options & OPT_OVERWRITE)) {
  377.     /* Overwrite not allowed if file does not exist */
  378.     if ((outfp = fopen(outFile, "r"))) {
  379.         if (! (options & OPT_SILENT)) {
  380.         MessageBox_error(hwnd,
  381.                  0,
  382.                  "File not overwritten",
  383.                  MB_OK | MB_ICONWARNING,
  384.                  "Preserving existing file %s.\r\r"
  385.                  "The new version of this file has been left in %s", 
  386.                  outFile, inFile);
  387.         }
  388.         fclose(outfp);
  389.         fclose(infp);
  390.         return 0;
  391.     }
  392.     /* To get here, output file does not exist */
  393.     }
  394.     if (!(outfp = fopen(outFile, "w"))) {
  395.     MessageBox_error(hwnd, 
  396.              AP_WIN32ERROR,
  397.              "Installation Problem",
  398.              MB_OK | MB_ICONSTOP,
  399.              "Cannot write to file %s", outFile);
  400.     fclose(infp);
  401.     return -1;
  402.     }
  403.  
  404.     while (fgets(inbuf, MAX_INPUT_LINE, infp)) {
  405.     char *pos;
  406.     char *outbuf;
  407.  
  408.     /* Quickly look to see if this line contains any
  409.      * @@ tokens. If it doesn't, we don't need to bother
  410.      * called expandLine() or taking a copy of the input
  411.      * buffer.
  412.      */
  413.     if (options & OPT_EXPAND) {
  414.             for (pos = inbuf; *pos; ++pos)
  415.         if (*pos == '@' && *(pos+1) == '@')
  416.             break;
  417.     }
  418.  
  419.     if (options & OPT_EXPAND && *pos) {
  420.         /* The input line contains at least one '@@' sequence, so
  421.          * call expandLine() to expand any sequences we know about.
  422.          */
  423.         outbuf = expandLine(inbuf, replaceTable);
  424.         if (outbuf == NULL) {
  425.         fclose(infp);
  426.         fclose(outfp);
  427.         MessageBox_error(hwnd,
  428.                  0,
  429.                  "Installation Problem",
  430.                  MB_OK|MB_ICONSTOP,
  431.                  "An error occurred during installation");
  432.         return -1;
  433.         }
  434.     }
  435.     else {
  436.         outbuf = NULL;
  437.     }
  438.  
  439.     /* If outbuf is NULL, we did not need to expand sequences, so
  440.      * just output the contents of the input buffer.
  441.      */
  442.     fwrite(outbuf ? outbuf : inbuf, 1, 
  443.            strlen(outbuf ? outbuf : inbuf), outfp);
  444.  
  445.     if (outbuf)
  446.         free(outbuf);
  447.     }
  448.     fclose(infp);
  449.     fclose(outfp);
  450.  
  451.     LogMessage("COPY: expanded %s to %s", inFile, outFile);
  452.  
  453.     if (options & OPT_DELETESOURCE) {
  454.     unlink(inFile);
  455.         LogMessage("COPY: deleted file %s", inFile);
  456.     }
  457.  
  458.     return 0;
  459. }
  460.  
  461. int FillInReplaceTable(HWND hwnd, REPLACETABLE table, char *szInst)
  462. {
  463.     REPLACEITEM *item;
  464.     for (item = table; item->tmpl; ++item) {
  465.     if (!strcmp(item->tmpl, "@@ServerRoot@@")) {
  466.         char *p;
  467.  
  468. #if NEED_SHORT_PATHS
  469.         int len;
  470.         len = GetShortPathName(szInst, NULL, 0);
  471.         if (len > 0) {
  472.         item->value = (char*)malloc(len+1);
  473.         GetShortPathName(szInst, item->value, len);
  474.         }
  475. #else
  476.         if ((item->value = strdup(szInst)) == NULL)
  477.             return -1;
  478. #endif
  479.         for (p = item->value; *p; p++)
  480.             if (*p == '\\') *p = '/';
  481.  
  482.         LogMessage("FillInReplaceTable tmpl=%s value=%s", item->tmpl, item->value);
  483.  
  484.         continue;
  485.     }
  486. #if NEED_FQDN
  487.     if (!strcmp(item->tmpl, "FQDN")) {
  488.         item->value = GetHostName(hwnd);
  489.         continue;
  490.     }
  491. #endif
  492.     }
  493.     return 0;
  494. }
  495.  
  496. /*
  497.  * actionTable[] contains things we do when this DLL is called by InstallShield
  498.  * during the install. It is like a simple script, without us having to
  499.  * worry about parsing, error checking, etc.
  500.  *
  501.  * Each item in the table is of type ACTIONITEM. The first element is the action 
  502.  * to perform (e.g. CMD_COPY). The second and third elements are filenames
  503.  * (e.g. for CMD_COPY, the first filename is the source and the second filename
  504.  * is the destination). The final element of ACTIONITEM is a set of options
  505.  * which apply to the current "command". For example, OPT_EXPAND on a CMD_COPY
  506.  * line, tells the copy function to expand @@ServerRoot@@ tokens found in the
  507.  * source file.
  508.  *
  509.  * The contents of this table are performed in order, top to bottom. This lets
  510.  * us expand the files to the *.conf.default names, then copy to *.conf only
  511.  * if the corresponding *.conf file does not already exist. If it does exist,
  512.  * it is not overwritten.
  513.  *
  514.  * Return 1 on success, 0 on error.
  515.  */
  516.  
  517. typedef enum {
  518.     CMD_COPY = 0,
  519.     CMD_RMDIR,
  520.     CMD_RM,
  521.     CMD_END
  522. } cmd_t;
  523.  
  524. typedef struct {
  525.     cmd_t command;
  526.     char *in;
  527.     char *out;
  528.     options_t options;
  529. } ACTIONITEM;
  530. typedef ACTIONITEM *ACTIONTABLE;
  531.  
  532. ACTIONITEM actionTable[] = {
  533.     /*
  534.      * Installation of the configuraton files. These are installed into the ".tmp"
  535.      * directory by the installer. We first move them to conf\*.default (overwriting
  536.      * any *.default file from a previous install). The *.conf-dist-win files
  537.      * are also expanded for any @@...@@ tokens. Then we copy the conf\*.default
  538.      * file to corresponding conf\* file, unless that would overwrite an existing file.
  539.      */
  540.     { CMD_COPY, ".tmp\\mime.types", "conf\\mime.types.default",
  541.     OPT_OVERWRITE|OPT_DELETESOURCE },
  542.     { CMD_COPY, ".tmp\\magic", "conf\\magic.default",
  543.     OPT_OVERWRITE|OPT_DELETESOURCE },
  544.     { CMD_COPY, ".tmp\\httpd.conf-dist-win", "conf\\httpd.conf.default", 
  545.     OPT_OVERWRITE|OPT_EXPAND|OPT_DELETESOURCE },
  546.     { CMD_COPY, ".tmp\\srm.conf-dist-win", "conf\\srm.conf.default", 
  547.     OPT_OVERWRITE|OPT_EXPAND|OPT_DELETESOURCE },
  548.     { CMD_COPY, ".tmp\\access.conf-dist-win", "conf\\access.conf.default", 
  549.     OPT_OVERWRITE|OPT_EXPAND|OPT_DELETESOURCE },
  550.  
  551.     /* Now copy to the 'live' files, unless they already exist */
  552.     { CMD_COPY, "conf\\httpd.conf.default", "conf\\httpd.conf", OPT_NONE },
  553.     { CMD_COPY, "conf\\srm.conf.default", "conf\\srm.conf", OPT_NONE },
  554.     { CMD_COPY, "conf\\access.conf.default", "conf\\access.conf", OPT_NONE },
  555.     { CMD_COPY, "conf\\magic.default", "conf\\magic", OPT_NONE },
  556.     { CMD_COPY, "conf\\mime.types.default", "conf\\mime.types", OPT_NONE },
  557.  
  558.     { CMD_COPY, ".tmp\\highperformance.conf-dist", "conf\\highperformance.conf-dist", 
  559.     OPT_EXPAND|OPT_OVERWRITE|OPT_DELETESOURCE },
  560.  
  561.     /* Move the default htdocs files into place, provided they don't already
  562.      * exist.
  563.      */
  564.     { CMD_COPY, ".tmp\\index.html", "htdocs\\index.html", OPT_DELETESOURCE|OPT_SILENT },
  565.     { CMD_RM, ".tmp\\index.html", NULL, OPT_SILENT },
  566.     { CMD_COPY, ".tmp\\apache_pb.gif", "htdocs\\apache_pb.gif", OPT_DELETESOURCE|OPT_SILENT },
  567.     { CMD_RM, ".tmp\\apache_pb.gif", NULL, OPT_SILENT },
  568.  
  569.     { CMD_RMDIR, ".tmp", NULL },
  570.  
  571.     { CMD_END, NULL, NULL, OPT_NONE }
  572. };
  573.  
  574. /*
  575.  * BeforeExit() is the DLL call from InstallShield. The arguments and
  576.  * return value as defined by the installer. We are only interested
  577.  * in the install directory, szInst. Return 0 on error and 1 on
  578.  * success (!?).
  579.  */
  580.  
  581. CHAR WINAPI BeforeExit(HWND hwnd, LPSTR szSrcDir, LPSTR szSupport, LPSTR szInst, LPSTR szRes)
  582. {
  583.     ACTIONITEM *pactionItem;
  584.     int end = 0;
  585.  
  586.     OpenLog(szInst, "install.log");
  587.     LogMessage("STARTED %s", VERSION);
  588.     LogMessage("src=%s support=%s inst=%s",
  589.         szSrcDir, szSupport, szInst);
  590.  
  591.     FillInReplaceTable(hwnd, replaceHttpd, szInst);
  592.  
  593.     pactionItem = actionTable;
  594.     while (!end) {
  595.  
  596.     LogMessage("command=%d in=%s out=%s options=%d",
  597.            pactionItem->command,
  598.            pactionItem->in ? pactionItem->in : "NULL",
  599.            pactionItem->out ? pactionItem->out : "NULL",
  600.            pactionItem->options);
  601.  
  602.     switch(pactionItem->command) {
  603.     case CMD_END:
  604.         end = 1;
  605.         break;
  606.     case CMD_COPY:
  607.         if (ExpandConfFile(hwnd, szInst, 
  608.                    pactionItem->in, 
  609.                    pactionItem->out,
  610.                    replaceHttpd,
  611.                    pactionItem->options) < 0) {
  612.         /* Error has already been reported to the user */
  613.         return 0;
  614.         }
  615.         break;
  616.     case CMD_RM: {
  617.         char inFile[MAX_INPUT_LINE];
  618.  
  619.         ap_snprintf(inFile, sizeof(inFile), "%s\\%s", szInst, pactionItem->in);
  620.         if (unlink(inFile) < 0 && !(pactionItem->options & OPT_SILENT)) {
  621.         MessageBox_error(hwnd, AP_WIN32ERROR, "Error during configuration",
  622.             MB_ICONHAND,
  623.             "Could not remove file %s", 
  624.             inFile);
  625.         return 0;
  626.         }
  627.         LogMessage("RM: deleted file %s", inFile);
  628.         break;
  629.     }
  630.     case CMD_RMDIR: {
  631.         char inFile[MAX_INPUT_LINE];
  632.  
  633.         ap_snprintf(inFile, sizeof(inFile), "%s\\%s", szInst, pactionItem->in);
  634.         if (rmdir(inFile) < 0) {
  635.         MessageBox_error(hwnd, AP_WIN32ERROR, "Error during configuration",
  636.             MB_ICONHAND,
  637.             "Could not delete temporary directory %s", 
  638.             inFile);
  639.         return 0;
  640.         }
  641.         LogMessage("RMDIR: deleted directory %s", inFile);
  642.         break;
  643.     }
  644.     default:
  645.         MessageBox_error(hwnd, 0, "Error during configuration",
  646.             MB_ICONHAND,
  647.             "An error has occurred during configuration\r"
  648.             "(Error: unknown command %d)", (int)pactionItem->command);
  649.         end = 1;
  650.         break;
  651.     }
  652.     pactionItem++;
  653.     }
  654.  
  655.     LogMessage("FINISHED OK");
  656.     CloseLog();
  657.  
  658.     return 1;
  659. }
  660.  
  661.  
  662. BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
  663. {
  664.     if (fdwReason == DLL_PROCESS_ATTACH)
  665.     hInstance = hInstDLL;
  666.     return TRUE;
  667. }
  668.